<?php 
namespace town\base;

class Route
{
	private static $obj    = null;

	private static $method = ['GET'=>1, 'POST'=>1, 'PUT'=>1, 'PATCH'=>1, 'DELETE'=>1];

	private $GET     = null;

	private $POST    = null;

	private $PATCH   = null;

	private $PUT     = null;

	private $DELETE  = null;

	public $current  = null;

	public $prefix   = null;

	public $currentFilter = null;


	/**
	 * 分析当前路由
	 * TODO::   GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的
	 * @return array 返回调用信息 控制器,方法,控制器,过滤器 ...再想
	 */
	private function dispatch()
	{
		// 获取当前路由
		$this->current = $this->_parseRouteUri();

		// 分析当前路由匹配的控制器
		$list  = $this->_parseRouteSet($this->current['method']);

		// 获取匹配路由
		$route = $this->_routeMatch($list, $this->current);

		return $route;
	}


	/**
	 * 解析开发设置的路由
	 * /user/{id}/name/{name}
	 * @param  string $methodSet 方法合集
	 * @return array
	 */
	private function _parseRouteSet($methodSet)
	{
		$list = [];
		$temp = $this->{$methodSet};
		if (is_array($temp)) {
			foreach ($temp as $key => $vo) {
				$route           = $this->_parseRouteOne($vo['local']);
				$route['method'] = $methodSet;
				$list[]          = array_merge($route, $vo);
			}
		}
		return $list;
	}


	/**
	 * 分析单个路由
	 * @param  string $local  url
	 * @param  string $method 路由集合
	 * @return array
	 */
	private function _parseRouteOne($local)
	{
	    $len   = 0;
	    $args  = [];
	    $local = '/'.trim($local, '/');
	    for ($i = strlen($local) - 1; $i >= 0; $i--) { 
	        switch ($local[$i]) {
	            case '{':
	                $pos = $pos-$len;
	                $arg_k = substr($local, $pos, $len);
	                $args[$arg_k] = ['pos'=>($pos-1), 'length'=>($len+2)]; // 
	                break;
	            case '}':
	                $pos = $i;
	                $len = 0;
	                break;
	            default:
	                $len++;
	                break;
	        }
	    }

	    $trans = $local;
	    foreach ($args as $arg_k => $val) {
	        $trans = substr_replace($trans, '*', $val['pos'], $val['length']);
	    }
	    $args = array_reverse($args);
	    return [
	        'local' => $local,
	        'trans' => $trans,
	        'args'  => $args
	    ];
	}


	/**
	 * 解析用户请求uri
	 * /user/1/avatar/rm
	 * @return array
	 */
	private function _parseRouteUri()
	{
	    $args  = [];
	    // 第一个'?'之前的数据   /user/1/avatar/rm
	    $local = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);;
	    if (strlen($local)<2) {
	    	$local = '/';
	    	$trans = '/';
	    } else {
	    	$local = ltrim($local, '/');
		    $temp  = explode('/', trim($local, '/'));
		    foreach ($temp as $key => &$val) {
		        if ($key % 2) {
		            $args[$temp[$key-1]] = $val;
		            $val = '*';
		        }
		    }
		    $trans  = '/'.implode('/', $temp);
	    }
		$method = $_SERVER['REQUEST_METHOD'];
	    return [
		    'method'=> $method,
	        'local' => $local,
	        'trans' => $trans,
	        'args'  => $args
	    ];
	}


	/**
	 * 获取匹配的路由
	 * @param  array  $list  路由集
	 * @param  array  $route 请求uri
	 * @return array|boolean 匹配失败返回false
	 */
	private function _routeMatch($list, $route)
	{
		$args = [];
		foreach ($list as $key => $val) {
			if ($val['trans'] != $route['trans']) {
				continue;
			}
			$keys        = array_keys($val['args']);
			$values      = array_values($route['args']);
			$val['args'] = array_combine($keys, $values);
			return $val;
		}

	    return false;
	}


	/**
	 * 设置路由
	 * @param string $method    [description]
	 * @param array  $arguments [description]
	 */
	private function setRoute($name, $arguments)
	{
		if (count($arguments) == 3) {
			list($local, $controller, $filter) = $arguments;
		} else {
			$filter = null;
			list($local, $controller) = $arguments;
		}

		if (empty($filter)) {
			$filter = [];
		}
		if (!is_array($filter)) {
			$filter = [$filter];
		}
		
		// set group args
		if ($this->currentFilter) {
			array_unshift($filter, $this->currentFilter);
		}

		if ($this->prefix) {
			$local = '/'.trim($this->prefix, '/').'/'.trim($local. '/');
		}

		$data = [
			'method'     => $name,  // 方法名
			'local'      => $local, // uri
			'controller' => $controller, // 控制器@方法
			'filter'     => $filter // 中间件
		];
		$this->{$name}[] = $data;
	}


	/**
	 * 设置分组
	 * @param  Closure $closure     闭包
	 * @param  string|array $filter 中间件名称
	 * @param  string|array $prefix 路由前缀
	 * @return object
	 */
	private function group($closure, $filter, $prefix = '')
	{
		if (!is_callable($closure)) {
			trigger_error('need type closure', E_USER_ERROR);
			return false;
		}

		if (empty($filter) || count($filter) < 1) {
			trigger_error('filter can\'t empty', E_USER_ERROR);
			return false;
		}

		$this->prefix      = $prefix;
		$this->currentFilter = $filter;
		$closure();
		unset($this->prefix);
		unset($this->currentFilter);
	}


	private function get($name)
	{
		if (property_exists($this, $name)) {
			return $this->{$name};
		}
	}


    public static function singleton()
    {
        if (static::$obj == null) {
            static::$obj = new static();
        }
        return static::$obj;
    }

	
	public function __call($name, $arguments)
	{
		if (method_exists($this, $name)) {
			call_user_func_array([$this, $name], $arguments);
		}
	}

	
	public static function __callStatic($name, $arguments)
	{
		$obj  = static::singleton();
		$name = strtoupper($name);

		if (array_key_exists($name, $obj::$method)) {
		    return call_user_func([$obj, 'setRoute'], $name, $arguments);
		}

		if (method_exists($obj, $name)) {
			return call_user_func_array([$obj, $name], $arguments);
		}

		throw new \Exception("method $name no exists", E_USER_NOTICE);
	}
	
}